using System;

namespace NetFrameworkExtensions.Utils
{
  [Serializable]
  public abstract class ReadonlyReferenceBase<T> : IReadonlyReference<T>
  {

    #region IReadonlyReference<T> Members

    public abstract T Value { get; }

    [NonSerialized]
    private EventHandler<ValueChangedEventArgs<T>> _valueChanged;
    public event EventHandler<ValueChangedEventArgs<T>> ValueChanged
    {
      add { _valueChanged += value; }
      remove { _valueChanged -= value; }
    }

    #endregion

    #region IReadonlyReference Members

    object IReadonlyReference.Value { get { return Value; } }

    public abstract bool CanChange
    {
      get;
    }

    [NonSerialized]
    private EventHandler<ValueChangedEventArgs<object>> _untypedValueChanged;
    public event EventHandler<ValueChangedEventArgs<object>> UntypedValueChanged
    {
      add { _untypedValueChanged += value; }
      remove { _untypedValueChanged -= value; }
    }

    #endregion

    protected virtual void OnValueChanged(T value, T previousValue)
    {
      var untypedValueChanged = _untypedValueChanged;
      if (untypedValueChanged != null)
        untypedValueChanged(this, new ValueChangedEventArgs<object>(value, previousValue));
      var valueChanged = _valueChanged;
      if (valueChanged != null)
        valueChanged(this, new ValueChangedEventArgs<T>(value, previousValue));
    }
    protected virtual void OnValueChanged(T value)
    {
      var untypedValueChanged = _untypedValueChanged;
      if (untypedValueChanged != null)
        untypedValueChanged(this, new ValueChangedEventArgs<object>(value));
      var valueChanged = _valueChanged;
      if (valueChanged != null)
        valueChanged(this, new ValueChangedEventArgs<T>(value));
    }
    protected virtual void CheckCanChange()
    {
      if (!CanChange) throw new InvalidOperationException(GlobalResources.Reference_CanChangeValue);
    }
  }
}